1
2
3
4
5
6
7 package ca.uhn.cache.impl;
8
9 import java.util.Iterator;
10
11 import org.apache.commons.logging.Log;
12 import org.apache.commons.logging.LogFactory;
13 import org.springframework.beans.factory.InitializingBean;
14
15 import ca.uhn.cache.IDataItem;
16 import ca.uhn.cache.IDataSource;
17 import ca.uhn.cache.IQuery;
18 import ca.uhn.cache.IQueryResult;
19 import ca.uhn.cache.ISemanticCache;
20 import ca.uhn.cache.exception.CacheException;
21 import ca.uhn.cache.exception.DataSourceException;
22 import ca.uhn.cache.util.QueryResultUtil;
23
24 /***
25 * An <code>IDataSource</code> that is an underlying <code>IDataSource</code>
26 * wrapped in a read-through cache.
27 *
28 * TODO: We allow a single result to correspond to multiple queries in
29 * IDataSource ... this might create a cache consistency problem ... if a query
30 * is performed, then we get remainder results, then the cached portion is
31 * purged, then we populate the cache with the remainder, then the descriptor of
32 * the remainder will include the cached portion which has been purged. We don't
33 * get this problem if we only allow one query per result.
34 *
35 * @author <a href="mailto:bryan.tripp@uhn.on.ca">Bryan Tripp </a>
36 * @version $Revision: 1.1 $ updated on $Date: 2005/01/24 22:52:33 $ by $Author:
37 * btripp $
38 */
39 public class SelfCachingDataSource implements IDataSource, InitializingBean {
40
41 private static final Log ourLog = LogFactory.getLog( SelfCachingDataSource.class );
42
43 private static final IQueryResult EMPTY_QUERY_RESULT = new QueryResult();
44
45 private ISemanticCache mySemanticCache;
46
47 private IDataSource myDataSource;
48
49 private int myMaxQueryGroups = -1;
50
51
52
53 /***
54 // * @param theCache cache that holds query results and may partially or completely answer queries
55 // * @param theSource original source of data to be cached / returned to caller as needed
56 // * @param theMaxRemainderQueries maximum number of remainder queries that can be used to obtain
57 // * the non-cached portion of a query result
58 // */
59
60
61
62
63
64
65
66
67
68
69 /***
70 * Default constructor.
71 */
72 public SelfCachingDataSource() {
73
74
75 }
76
77 /***
78 * Note that there is no optimization for sending multiple queries at once
79 * (queries are executed in series).
80 *
81 * @see ca.uhn.cache.IDataSource#execute(ca.uhn.cache.IQuery[])
82 */
83 public IQueryResult execute( IQuery[] theQueries ) throws DataSourceException {
84 if (theQueries.length == 0) {
85 throw new IllegalArgumentException( "The list of queries is empty" );
86 }
87
88 IQueryResult result = execute( theQueries[0] );
89
90
91 for (int i = 1; i < theQueries.length; i++) {
92 Iterator nextResults = execute( theQueries[i] ).iterator();
93 while (nextResults.hasNext()) {
94 result.add( (IDataItem) nextResults.next() );
95 }
96 }
97
98 return result;
99 }
100
101 private IQueryResult execute( IQuery theQuery ) throws DataSourceException {
102
103
104
105 IQueryResult retVal;
106
107 boolean useCachedResult = true;
108
109 IQueryResult cachedResult = null;
110 try {
111 cachedResult = getSemanticCache().get( theQuery );
112 }
113 catch (CacheException e) {
114 useCachedResult = false;
115 ourLog.error( "Exception thrown while executing the get method of the cache", e );
116 }
117
118 IQuery[] remainders = null;
119 if ( useCachedResult == true ) {
120 try {
121 remainders = getSemanticCache().remainder( theQuery, myMaxQueryGroups );
122 }
123 catch (CacheException e) {
124 useCachedResult = false;
125 ourLog.error( "Exception thrown while executing the remainder method of the cache", e );
126 }
127 }
128
129 IQueryResult sourceResult = EMPTY_QUERY_RESULT;
130 if ( useCachedResult == true ) {
131 if ( remainders.length != 0) {
132 sourceResult = getDataSource().execute( remainders );
133 }
134 }
135 else {
136 sourceResult = getDataSource().execute( new IQuery[] { theQuery } );
137 }
138
139 if ( useCachedResult == true && !sourceResult.isEmpty() ) {
140 try {
141
142 for (int i = 0; i < remainders.length; i++) {
143 IQuery remainderQuery = remainders[i];
144
145 getSemanticCache().put( remainderQuery, QueryResultUtil.filter( sourceResult, remainderQuery ) );
146 }
147 }
148 catch (CacheException e) {
149 ourLog.error( "Exception thrown while executing the put method of the cache", e );
150 }
151 }
152
153 IQueryResult filteredSourceResult = QueryResultUtil.filter(sourceResult, theQuery);
154
155 if ( useCachedResult == true ) {
156 retVal = cachedResult.append( filteredSourceResult );
157 }
158 else {
159 retVal = filteredSourceResult;
160 }
161
162 return retVal;
163 }
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195 /***
196 * @return Semantic cache that holds query results and may partially or completely answer queries.
197 */
198 public ISemanticCache getSemanticCache() {
199 return mySemanticCache;
200 }
201
202 /***
203 * @param theSemanticCache The semantic cache to set.
204 */
205 public void setSemanticCache( ISemanticCache theSemanticCache ) {
206 mySemanticCache = theSemanticCache;
207 }
208
209 /***
210 * @return The maximum number of queries that will be sent to the underlying data source at a time.
211 *
212 * @see ISemanticCache#remainder(IQuery, int)
213 */
214 public int getMaxQueryGroups() {
215 return myMaxQueryGroups;
216 }
217
218 /***
219 * @param theMaxQueryGroups The maxQueryGroups to set.
220 */
221 public void setMaxQueryGroups( int theMaxQueryGroups ) {
222 myMaxQueryGroups = theMaxQueryGroups;
223 }
224
225 /***
226 * The underlying data source.
227 *
228 * @return Returns the source.
229 */
230 public IDataSource getDataSource() {
231 return myDataSource;
232 }
233
234 /***
235 * @param theDataSource The source to set.
236 */
237 public void setDataSource( IDataSource theDataSource ) {
238 myDataSource = theDataSource;
239 }
240
241 /***
242 * {@inheritDoc}
243 */
244 public void afterPropertiesSet() throws Exception {
245 assert getDataSource() != null;
246 assert getSemanticCache() != null;
247 assert getMaxQueryGroups() != -1;
248 }
249
250
251
252 }